
#ifndef __WEBSERVER__
#define __WEBSERVER__

#include <iostream>
#include "TcpSocket.hpp"
#include <unistd.h>
#include <thread>
#include <signal.h>
#include <functional>
#include "Entrance.hpp"
#include "ThreadPool.hpp"
#include <sys/socket.h>
#include <poll.h>

// 尝试select
#include <sys/select.h>

typedef std::function<void *(const int)> function;

#define QUEUE_TASK_NUM 10 // 任务队列最大数

#define POLLFD_MAX_ 50 // 设置poll最大监听标识符量

// 制作一个初始化服务端的类型——使用单例模式

template <class T>
class webserver
{
    typedef ThreadPool<T *> thread_pool;

private:
    int _port = -1;
    int _server_listen_socket = -1;
    thread_pool *_st = nullptr;

    struct pollfd *pollfd_array;
    int nfds = 0;

public:
    webserver()
    {
        signal(SIGPIPE, SIG_IGN);
        // 防止send，向关闭管道写入，导致webserver崩溃
    }

    void initial(int _port, thread_pool *th_pool)
    {
        MySocket tool;
        _server_listen_socket = tool._socket_set();
        // 设置复用端口号
        int tmp = 1;
        if (setsockopt(_server_listen_socket, SOL_SOCKET, SO_REUSEADDR, &tmp, sizeof(tmp)) < 0)
            std::cout << "setsockopt fail" << std::endl;

        tool.bind_set(_server_listen_socket, _port);
        Logmessage(INFO, "服务端初始化成功");

        // 初始化pollfd数组
        pollfd_array = new struct pollfd[POLLFD_MAX_];
        for (int i = 0; i < POLLFD_MAX_; i++)
        {
            pollfd_array[i].fd = -1;
            pollfd_array[i].events = POLLIN;
        }

        // 启用线程池
        _st = th_pool;
    }

    void work_begin()
    {
        MySocket::listen_run(_server_listen_socket);
        pollfd_array[nfds].fd = _server_listen_socket;
        nfds++;

        while (1)
        {
            int n = poll(pollfd_array, nfds, 1000);
            if (n < 0)
            {
                Logmessage(ERROR, "poll fail errno %d: %s", errno, std::to_string(errno).c_str());
                exit(-1);
            }
            else if (n == 0)
            {
                continue;
            }

            for (int i = 0; i < nfds; i++)
            {
                // listen：新连接到来
                if (pollfd_array[i].revents == POLLIN && i == 0)
                {
                    Logmessage(INFO, "poll get a new connect");
                    accepter();
                }
                else if (pollfd_array[i].revents == POLLIN)
                {
                    // Logmessage(INFO, "fd: %d 已读资源就绪", pollfd_array[i].fd);
                    // 读事件就绪：read,recv(文件描述符已收到资源，请尽快读取)
                    taskpush(pollfd_array[i].fd);
                }
                else if (pollfd_array[i].revents == POLLOUT)
                {
                    Logmessage(INFO, "fd: POLLOUT");
                }
            }
        }
    }

private:
    bool accepter()
    {
        // 检测到连接
        sockaddr_in cline;
        uint16_t cline_prot;
        int actual_socket = MySocket::accept_run(_server_listen_socket, &cline, &cline_prot);
        if (actual_socket != -1)
        {
            Logmessage(INFO, "connect success 标识符:%d", actual_socket);
        }
        pollfd_array[nfds].fd = actual_socket;
        nfds++;
        return true;
    }

    int taskpush(int socket)
    {
        // 接收到请求后，想任务池中添加任务---线程池方案
        if (_st->Get_queue_task_reserver_size() < QUEUE_TASK_NUM)
        {
            Thread_Task *task = new Thread_Task(socket);
            _st->push(task);
            _st->swap_queue(QUEUE_TASK_NUM);
        }
    }
};

#endif
